package org.batatasframework.bytecode;

import java.lang.reflect.Field;

import org.batatasframework.bytecode.spi.AsmLoadable;
import org.batatasframework.bytecode.spi.AsmInstancable;
import org.batatasframework.bytecode.spi.AsmStorable;
import org.springframework.asm.ClassWriter;
import org.springframework.asm.MethodVisitor;
import org.springframework.asm.Opcodes;

/**
 * 一个类的成员变量
 * @author jackson
 *
 */
public class FieldAsminfo implements AsmLoadable, AsmStorable, AsmInstancable{
	/** 如果这个字段是动态生成的，则这个字段值为null */
	private Field sourceField;
	private final ClassAsminfo owner;
	private final String name;
	private final ClassAsminfo typeClass;
	/** 方法的范围 */
	private final int access;
	
	private String signature;
	
	private Object value;
	
	public FieldAsminfo(ClassAsminfo owner, Field field){
		this(owner, ClassAsminfo.parseModifiers(field), field.getName(), new ClassAsminfo(field.getType()));
		this.sourceField = field;
	}
	
	public FieldAsminfo(ClassAsminfo owner, int access, String name, ClassAsminfo typeClass){
		this.owner = owner;
		this.access = access;
		this.name = name;
		this.typeClass = typeClass;
	}
	
	public Field getSourceField() {
		return sourceField;
	}
	
	/** 生成类的成员变量 */
	public void makeField(ClassWriter classWriter){
		classWriter.visitField(access, name, typeClass.toDes(), signature, value).visitEnd();
	}
	
	/** 在方法体里对类成员变量进行赋值 */
	@Override
	public void store(MethodVisitor visitor){
		_visit(visitor, Opcodes.PUTFIELD);
	}
	
	@Override
	public void store(MethodVisitor visitor, AsmLoadable value) {
		value.load(visitor, typeClass);
		_visit(visitor, Opcodes.PUTFIELD);
	}
	
	/* 创建一个成员变量的对象 */
	@Override
	public void instance(MethodVisitor visitor) {
		typeClass.instance(visitor);
		_visit(visitor, Opcodes.PUTFIELD);
	}
	
	/** 在方法体里对类成员变量进行取值 */
	@Override
	public void load(MethodVisitor visitor, ClassAsminfo targetType){
		_visit(visitor, Opcodes.GETFIELD);
		targetType.cast(visitor, typeClass);
	}
	
	@Override
	public void load(MethodVisitor visitor) {
		_visit(visitor, Opcodes.GETFIELD);
	}
	
	private void _visit(MethodVisitor visitor, int type){
		visitor.visitFieldInsn(type, owner.getClassPath(), name, typeClass.toDes());
	}
}
